package hibernatemock;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SuppressWarnings("unchecked") public class FluentApi {

	private ReflectionUtil reflectionUtil = new ReflectionUtil();
	private SmartMap<SmartClass, Object> smartMap = new SmartMap<SmartClass, Object>();
	private Map<Field, Object> specialFields = new HashMap<Field, Object>();
	private List<Field> avoidCyclic = new ArrayList<Field>();

	// when
	public FluentApi putKey(Class<?> key) {
		SmartClass smartClass = new SmartClass(key);
		smartMap.remove(smartClass);
		smartMap.put(smartClass, null);
		return this;
	}

	// deliver whole class
	public void putValue(Object value) {
		smartMap.put(smartMap.getLastKey(), value);
	}

	// deliver property
	public void setValue(String fieldName, Object fieldValue) {
		Object bean = this.getValue(smartMap.getLastKey());
		specialFields.put(reflectionUtil.getField(bean.getClass(), fieldName), fieldValue);
	}

	// any
	public Object getValue(SmartClass smartClass) {
		Object value = smartMap.get(smartClass);
		if (reflectionUtil.isUserType(value.getClass())) {
			for (Field field : value.getClass().getDeclaredFields()) {
				if (specialFields.containsKey(field)) {
					reflectionUtil.setProperty(value, field, specialFields.get(field));
				} else {
					if (!avoidCyclic.contains(field) && !Modifier.isStatic(field.getModifiers())) {
						avoidCyclic.add(field);
						SmartClass smartClassField = new SmartClass(field);
						Object property = this.getValue(smartClassField);
						reflectionUtil.setProperty(value, field, property);
						if (smartClassField.isCollection())
							((Collection) property).add(this.getValue(new SmartClass(smartClassField.getBeanType())));
					}
				}
			}
		}
		return value;
	}

	public void clear() {
		avoidCyclic.clear();
	}
}
